# -- coding: utf-8 --
'''
how to use this function:
1 for Mac, 打开终端
2 输入以下命令：
python /Users/wangeon/Documents/Majiang.py
'''

'''
Functions:
1 计算出手上的牌可以胡哪几张。
2 计算出手上牌应该出哪张才能胡最多牌
3 计算出手上有吃有碰的情况下打哪张最好和胡哪几张。
优化碰了以后的程序

need:
计算出可以胡的牌的张数
计算出刚刚接到的牌打哪几张以后可以生成最好的组合。
计算出别人手里的牌是什么，牌桌下面剩的牌的概率。
'''

import copy
import sys
import random

a = [1,2,3,4,5,6,7,8,9]
b = ["t","w","b"]
c = []

def build_whole_majiang():
    for i in range(len(b)):
        for j in range(len(a)):
            for times in range(4): #一种牌一共有4张
                 c.append(b[i]+str(a[j]))
    return c


def is_same_type(pai):
    pai.sort()
    len_pai = len(pai)
    pai_type = ""
    type_kinds = 0
    for card in pai:
        if pai_type!=card[0:len(pai[0])-1]:
            type_kinds += 1
            pai_type = card[0:len(pai[0])-1]
    if type_kinds==1:
        return True
    else:
        return False


def is_dui(pai):
    pai.sort()
    len_pai = len(pai)
    yes = 0
    for i in pai:
        pai.remove(i)
        if i in pai:
            yes = 1
    if yes == 0:
        return False
        #print("没有一对")
    elif yes == 1:
        if len_pai==2:
            #print("有一对")
            return True
    
def is_zi(pai):
    pai.sort()
    len_pai = len(pai)
    pai_type = 0
    if pai[0][0:len(pai[0])-1]==pai[1][0:len(pai[0])-1] and pai[1][0:len(pai[0])-1]==pai[2][0:len(pai[0])-1]:
        pai_type=1
    else:
        pai_type=0
            
    if pai_type==1 and len_pai==3:
        if int(pai[2][-1])-int(pai[1][-1])==1 and int(pai[2][-1])-int(pai[0][-1])==2:
            #print("是一字")
            return True
        elif int(pai[2][-1])==int(pai[1][-1]) and int(pai[2][-1])==int(pai[0][-1]):
            #print("是一字")
            return True
    else:
        pass
        #print("不是一字")
        


def is_win(pai0):
    pai0.sort()
    if optimize(pai):
        for i in range(5):
            pai = copy.deepcopy(pai0)  #深拷贝，不然就相当于是赋值，删除时会把两个list的对应元素都删除。
            len_zi=0
            print("testing dui is",[pai[0+3*i],pai[1+3*i]])
            if is_dui([pai[0+3*i],pai[1+3*i]]):
                pai.remove(pai[0+3*i])
                pai.remove(pai[0+3*i])
                for j in range(4):
                    if is_zi([pai[0+3*j],pai[1+3*j],pai[2+3*j]]):
                        len_zi += 1
                if len_zi == 4:
                    print("胡了！")
                
                
'''
pai1 = ["wan1","wan1","wan1","wan2","wan2","wan2","wan4","wan5","wan6","wan7","wan8","wan9","tiao1","tiao1"]

is_win(pai1)
'''
        

def user_input(x=''):
    y = str(x)+raw_input()
    return y if y != 'byebye' else sys.exit(0)

# 出牌的程序
def update_cards(pai):
    print("please input the card you are going to send out:")
    x = user_input()
    while x not in pai:
        print("please input only the cards you have in hand, thanks.")
        print("Now your cards are: "+str(pai))
        x = user_input()
    if x in pai:
        pai.remove(x)
        print("Now your cards are: "+str(pai))
    print("please input the card you get this turn:")
    y = user_input()
    pai.append(y)
    return pai

pai = ['b1','b2','b1','b3','b3','b3','b4','b5','b5','b6','b6','b6','t7','w8']
#print(update_cards(pai))

def type_calculation(pai):
    w,t,b= 0,0,0
    w_pool = []
    t_pool = []
    b_pool = []
    for card in pai:
        if card[0:len(pai[0])-1] == 'w':
            w+=1
            w_pool.append(card)
        elif card[0:len(pai[0])-1] == 't':
            t+=1
            t_pool.append(card)
        else:
            b+=1
            b_pool.append(card)
    w_pool.sort()
    t_pool.sort()
    b_pool.sort()
    return w,t,b,w_pool,t_pool,b_pool
    

def optimize_1st(pai): #三墩牌变成两墩的方法
    print("Now your cards are: "+str(pai))
    w,t,b,diff_w,diff_t,diff_b = 0,0,0,0,0,0
    w,t,b,w_pool,t_pool,b_pool = type_calculation(pai)

    while w>0 and t>0 and b>0:
        if str([w,t,b]).count(str(min([w,t,b])))==2 and min([w,t,b])!=1:
            if w==min([w,t,b]):
                for card in range(len(w_pool)-1):
                    diff_w += int(w_pool[card+1][-1])-int(w_pool[card][-1])
            if t==min([w,t,b]):
                for card in range(len(t_pool)-1):
                    diff_t += int(t_pool[card+1][-1])-int(t_pool[card][-1])
            if b==min([w,t,b]):
                for card in range(len(b_pool)-1):
                    diff_b += int(b_pool[card+1][-1])-int(b_pool[card][-1])
            print(diff_b,diff_t,diff_w)
            min_kind = 'w' if diff_w==max([diff_w,diff_t,diff_b]) else 't' if diff_t==max([diff_w,diff_t,diff_b]) else 'b'
            print("you should send out any card in type "+min_kind)
            update_cards(pai)
            w,t,b,w_pool,t_pool,b_pool = type_calculation(pai)
        else:
            min_kind = 'w' if w==min([w,t,b]) else 't' if t==min([w,t,b]) else 'b'
            print("you should send out any card in type "+min_kind)
            update_cards(pai)
            w,t,b,w_pool,t_pool,b_pool = type_calculation(pai)
    if min([w,t,b]) == 0 and str([w,t,b]).count('0')==1:
        print('now you can decide whether you want to do Flush.')
        print("请输入:(打清一色的话请输入Y,不打清一色的话请输入N)")
        in_content = user_input()
        if in_content == "Y" or in_content == "y":
            print("开始清一色战术！")
            print("Now your cards are: "+str(pai))
            while is_same_type(pai)==False:
                type_kinds = [w,t,b]
                type_kinds.sort()
                middle_kind = 'w' if w==type_kinds[1] else 't' if t==type_kinds[1] else 'b'
                print("please send out any card in type "+middle_kind) #三个数中的中位数
                update_cards(pai)
            return pai
        elif in_content == "N" or in_content == "n":
            print("开始小胡战术！")
            return pai
        else:
            print("你输入的内容有误，请重输入！")

    if str([w,t,b]).count('0')==2:
        print('Now you should do Flush')
        return pai

#pai = ['b1','b2','b1','b3','b3','b3','b4','b5','b5','b6','b6','b6','t7','w8']
#optimize_1st(pai)

def optimize_2nd(pai): #清一色的出牌策略
    pai.sort()
    diff,diff_before,diff_after = 0,0,0
    card_memory,diff_memory = "",0
     
    for card in range(len(pai)):
        diff = 0
        diff_before = 0
        diff_after = 0
        pai_type = 0
        if card!=0 and card!=len(pai)-1:  #不是第一张或者最后一张牌
            if is_zi([pai[card-1],pai[card],pai[card+1]])==False:  #不是一句话
                if pai[card][0:len(pai[0])-1]==pai[card+1][0:len(pai[0])-1] and pai[card-1][0:len(pai[0])-1]==pai[card][0:len(pai[0])-1]:  #是同一类的牌
                    diff_after += int(pai[card+1][-1])-int(pai[card][-1])
                    diff_before += int(pai[card][-1])-int(pai[card-1][-1])
                    diff = diff_before+diff_after
        elif card == 0: #第一张牌时
            diff_after = int(pai[card+1][-1])-int(pai[card][-1])
            diff = diff_after
        elif card == len(pai)-1: #最后一张牌
            diff_before += int(pai[card][-1])-int(pai[card-1][-1])
            diff = diff_before
        if diff>diff_memory: #记录下差距最明显的那张牌
            card_memory = pai[card]
            diff_memory = diff
        print(diff,pai[card],card_memory)
    return card_memory

        
#print("please send out card "+optimize_2nd(pai))
    


def try_options(pai0):
    # 这里计算的是手里13张牌的时候，配合打出牌的程序一起使用才有指导意义最好。
    pai0.sort() #先给牌做一个排序，也即理牌
    win_cards = [] #创建好可以赢的牌
    len_zi=0 #创建好字的长度
    zi_number = (len(pai0)-1)/3 #计算出一共有几个顺字

    #start testing duizi NOT in hand. 计算手里没有对子的情况
    for i in range(len(pai0)-1): 
        len_zi=0
        pai = copy.deepcopy(pai0) #复制一下牌，不然无法复原
        pai.remove(pai[i]) #移除循环里轮到的这张牌
        for j in range(zi_number): #顺字长度里循环
            if is_zi([pai[0+3*j],pai[1+3*j],pai[2+3*j]]): #每3个计算一下是否可以合成顺字
                len_zi += 1 #如果可以合成就统计+1
        if len_zi == zi_number: #如果最后所有的三张都可以组成顺字了，那么就说明现在手里是缺少这个对子的。
            #print('we can win with',pai0[i])
            win_cards.append(pai0[i]) #把这张单独的牌加入赢牌库里

    #start testing with duizi in hand. 开始测试对子已经在手里的情况
    #取出两张牌以后，剩下的牌是否可以组成一个将+都是字的组合
    zi_number = (len(pai0)-4)/3 #计算出一共有几个顺字，由于手里有对子，所以减去2，再加上有两张还没有组成顺字，所以一共减去4
    for k in range(len(pai0)-2): #循环长度要减去手里的对子长度
        lenz_zi=0 #字的数量要清零
        pai1 = copy.deepcopy(pai0) #再次拷贝手牌
        if int(pai0[k+1][-1])-int(pai0[k][-1])<=1 and str(pai0[k][0:len(pai0[k])-1])==str(pai0[k+1][0:len(pai0[k+1])-1]): #牌是同一类，而且牌是连着的或者同一张的。
            #去掉这两张手牌  
            pai1.remove(pai1[k]) 
            pai1.remove(pai1[k])
            
            for i in range(zi_number+1): #在顺字的长度里循环
                len_zi=0
                pai = copy.deepcopy(pai1)
                if is_dui([pai[0+3*i],pai[1+3*i]]): #如果循环到的两张牌是对子的话
                    pai.remove(pai[0+3*i])
                    pai.remove(pai[0+3*i])
                    if (len(pai0)-1)/3>0: #还有待检查的牌的情况下
                        for j in range(zi_number): #在剩下的牌里，按顺字的数量来循环
                            if is_zi([pai[0+3*j],pai[1+3*j],pai[2+3*j]]): #判断是否是字
                                len_zi += 1
                        if len_zi == zi_number: #如果剩下的牌都是顺字了
                            #print("we can win with",pai0[k],pai0[k+1])
                            if pai0[k]==pai0[k+1] and pai0[k] not in win_cards: #如果去除的两张牌一样
                                win_cards.append(pai0[k]) #在赢牌库里添加去除的这张牌
                            if pai0[k]!=pai0[k+1] and pai0[k] not in win_cards: #确定牌的数字是在0-9之间 #如果去掉的两张牌不一样,添加前后两张
                                win_cards.append(str(pai0[k][0:len(pai0[k])-1])+str(int(pai0[k][-1])-1)) if int(pai0[k][-1])!=1 else "" #赢牌库里添加两张牌的前一张牌
                                win_cards.append(str(pai0[k+1][0:len(pai0[k+1])-1])+str(int(pai0[k+1][-1])+1)) if int(pai0[k+1][-1])!=9 else '' #赢牌库里添加两张牌的后一张牌
                    else:
                        win_cards.append("this is so obviously...you don't need me")

    win_cards=list(set(win_cards)) #把牌库转化为list
    win_cards.sort() #排序方便人看

    #print(win_cards)
    return win_cards
                    
#try_options(pai)


def best_options(pai0):
    #pai = copy.deepcopy(pai0) #复制手牌
    pai0.sort() #排序
    cards_numbers = 0
    winning_cards_memory = 0 #缓存赢牌数统计
    j = str() #记录是否已经计算过重复的牌
    for i in pai0:
        pai = copy.deepcopy(pai0) #每次循环之前先回复手牌至初始状态
        pai.remove(i)
        winning_cards = try_options(pai) #算出除去这张以后的赢牌库
        for cards in winning_cards: #对赢牌库里的牌判断还有多少张
            cards_numbers = 0 
            if cards in pai0: #如果手里已经有可以赢的牌
                num = str(pai0).count(cards) #统计手里已经有的牌
                cards_numbers += 4 - num #一副牌一种最多4张
            #还需要添加如果手里没有赢牌库里的牌的话，那么就只需要减去已经被别人打出的牌
                
        if try_options(pai)!=[] and j!=i: #可赢牌不为空的话而且这张牌还没有被计算过的话。
            print('if I send out card '+i+", then I can win with "+str(len(winning_cards))+
                  " kind of card. There are "+str(cards_numbers)+" cards left to win. And my winning cards are:"+str(winning_cards))
        if len(winning_cards)>winning_cards_memory: #如果现在的赢牌数量超过缓存的赢牌数，
            winning_cards_memory = winning_cards #那么就更新缓存至现在的赢牌数
        j = i #记录已经被统计过的牌。因为已经做过排序所以可以直接赋予现在的值即可。
    return True if winning_cards_memory != 0 else False


'''
# 输入手上的牌，并生成对应的list
x = raw_input()
pai3=x.split(",")
print("Now you have "+str(pai3))

# 完成计算
best_options(pai3)
print("\n")
'''



all_pai = build_whole_majiang()

pai = ['b1','b2','b1','b3','b3','b3','b4','b5','b5','b6','b6','b6','t7','w8']

def cards_out_there(pai,all_pai): #所有除了手牌外的牌
    for cards in pai:
        try:
            all_pai.remove(cards)
        except:
            print('there is something weired in given pai')

    return all_pai,len(all_pai)

cards_out_there, cards_out_there_nums = cards_out_there(pai,all_pai)

def cards_pool(given_cards, all_cards): #除了所有玩家手牌后，所有的牌
    for cards in given_cards:
        try:
            all_cards.remove(cards)
        except:
            print("There is something weired in the given cards")
    return all_cards

#生成随机的牌

random_cards = random.sample(cards_out_there,39) #随机生成其他三家的牌

print(cards_out_there, random_cards)

cards_pool = cards_pool(random_cards, cards_out_there)

print(len(cards_pool))


#最终自动化主程序：
def majiang(pai):

    #邀请Human输入牌
    print("Welcome to Majiang App - Xuezhandaodi!, please input your cards now:")
    #x = raw_input()
    #pai=x.split(",")
    
    if len(pai)>14 or ((len(pai)-1)%3!=0 and (len(pai)-2)%3!=0):
        print("You made mistakes in managing cards!!! 88~!")
        sys.exit(0)

    #拿到一副牌先判断是否是3墩，如果是开始优化,并询问human是否要打清一色
    optimize_1st(pai)
     
    #如果不打清一色，那么进入小胡战术，需要继续优化
    
    #打清一色的话，在上面的Opt1st里面已经涵盖了。会优化至手里的牌只有一个颜色为止

    while True:
        #每打出一张牌，测试是否有机会变成win，没有的话继续优化
        #每打出一张牌，测试是否有机会变成win，如果有，跟随接牌的情况实时更新
        best_options(pai)
        update_cards(pai)
    

    #随时显示现在player手里的牌，也同时允许player update牌，update后自动从最开始判断

#majiang(pai)

